package func.study.concurrency.c5;

import org.junit.Assert;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Semaphore;

/**
 * 使用信号量，构建有界集合
 * Created by chenyao on 2017/7/17.
 */
public class BoundedHashSet<T> {

    private Set<T> set;
    private Semaphore availableItems;
    private Semaphore availableSpaces;

    public BoundedHashSet(int bound) {
        set = new HashSet<>(bound);
        availableItems = new Semaphore(0);
        availableSpaces = new Semaphore(bound);
    }

    public boolean add(T t) throws InterruptedException {
        availableSpaces.acquire();
        boolean isAdd = false;
        try {
            synchronized (set) {
                isAdd = set.add(t);
            }
        } finally {
            if(isAdd) {
                availableItems.release();
            } else {
                availableSpaces.release();
            }
        }
        return isAdd;
    }

    public boolean remove(T t) throws InterruptedException {
        availableItems.acquire();
        boolean remove = false;
        synchronized (set) {
            remove = set.remove(t);
        }
        if(remove) {
           availableSpaces.release();
        } else {
            availableItems.release();
        }
        return remove;
    }

    public boolean isEmpty() {
        return availableItems.availablePermits() == 0;
    }

    public boolean isFull() {
        return availableSpaces.availablePermits() == 0;
    }

    public static void main(String[] args) throws InterruptedException {

    }

    /**
     * 测试单线程环境
     * @throws InterruptedException
     */
    static void singleTest() throws InterruptedException {
        BoundedHashSet<Integer> set = new BoundedHashSet<>(10);
        Assert.assertTrue(set.isEmpty() && !set.isFull());
        for (int i = 0; i < 10; i++) {
            set.add(i);
        }
        Assert.assertTrue(set.isFull());
        Assert.assertFalse(set.isEmpty());
    }







}
